#include <iostream>
#include <memory>

// Step 1: Define Operation Classes
class Cal 
{
public:
    virtual void performOperation(int a, int b) = 0;
    virtual ~Cal() {} // Base class should have virtual destructor
};

class Add : public Cal 
{
public:
    void performOperation(int a, int b) override {
        std::cout << "Addition result: " << (a + b) << std::endl;
    }
};

class Sub : public Cal 
{
public:
    void performOperation(int a, int b) override {
        std::cout << "Subtraction result: " << (a - b) << std::endl;
    }
};

class Mul : public Cal 
{
public:
    void performOperation(int a, int b) override {
        std::cout << "Multiplication result: " << (a * b) << std::endl;
    }
};

class Div : public Cal 
{
public:
    void performOperation(int a, int b) override {
        if (b != 0)
            std::cout << "Division result: " << (a / b) << std::endl;
        else
            std::cerr << "Error: Division by zero!" << std::endl;
    }
};

// Step 2: Define Factory Classes
class Factory 
{
public:
    virtual std::shared_ptr<Cal> createOperation() = 0;
    virtual ~Factory() {} // Base class should have virtual destructor
};

class AddFactory : public Factory 
{
public:
    std::shared_ptr<Cal> createOperation() override {
        return std::make_shared<Add>();
    }
};

class SubFactory : public Factory 
{
public:
    std::shared_ptr<Cal> createOperation() override {
        return std::make_shared<Sub>();
    }
};

class MulFactory : public Factory 
{
public:
    std::shared_ptr<Cal> createOperation() override 
    {
        return std::make_shared<Mul>();
    }
};

class DivFactory : public Factory 
{
public:
    std::shared_ptr<Cal> createOperation() override 
    {
        return std::make_shared<Div>();
    }
};

// Step 3: Implement Operation Factory
class OperationFactory 
{
public:
    static std::shared_ptr<Cal> createOperation(const std::string& operation) 
    {
        if (operation == "add") 
        {
            return std::make_shared<Add>();
        } 
        else if (operation == "sub") 
        {
            return std::make_shared<Sub>();
        } 
        else if (operation == "mul") 
        {
            return std::make_shared<Mul>();
        } 
        else if (operation == "div") 
        {
            return std::make_shared<Div>();
        } 
        else 
        {
            std::cerr << "Error: Invalid operation requested!" << std::endl;
            return nullptr;
        }
    }
};

int main() {
    // Step 4: Client Code
    int a = 10, b = 5;
    
    std::shared_ptr<Cal> addOp = OperationFactory::createOperation("add");
    if (addOp)
        addOp->performOperation(a, b);
    
    std::shared_ptr<Cal> subOp = OperationFactory::createOperation("sub");
    if (subOp)
        subOp->performOperation(a, b);
    
    std::shared_ptr<Cal> mulOp = OperationFactory::createOperation("mul");
    if (mulOp)
        mulOp->performOperation(a, b);
    
    std::shared_ptr<Cal> divOp = OperationFactory::createOperation("div");
    if (divOp)
        divOp->performOperation(a, b);
    
    return 0;
}
